package routers

import (
	rediscache "ahutoj/web/cache/redis"
	"ahutoj/web/controller"
	_ "ahutoj/web/docs"
	"ahutoj/web/io/constanct"
	"ahutoj/web/io/request"
	"ahutoj/web/io/response"
	"ahutoj/web/middlewares"
	"ahutoj/web/utils"
	"net/http"
	"reflect"
	"time"

	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"

	"github.com/gin-contrib/pprof"
	"github.com/gin-gonic/gin"
	"github.com/goccy/go-json"
)

func InitServer() {
	conf := utils.GetConfInstance()
	switch conf.Mode {
	case gin.DebugMode:
		gin.SetMode(gin.DebugMode)
	case gin.ReleaseMode:
		gin.SetMode(gin.ReleaseMode)
	}

	router := gin.Default()
	router.Use(middlewares.Cors())
	registerRouters(router)

	// 注册 pprof 监控 仅仅在 开发阶段可看
	if conf.Mode == gin.DebugMode {
		pprof.Register(router)
	}

	InitRouters(router, conf.Host+conf.Port)
	// 404
	router.NoRoute(NotFindRegister)

	router.Run(conf.Port)

}

func registerRouters(router *gin.Engine) {

	// 相当于接口 /api/ 这组路径
	router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)).Use(middlewares.Cors())
	router.GET("/ws", controller.CreateWsClient)
	apiRouter := router.Group("/api")
	{
		apiRouter.GET("/ping", PingTest) // 测试网络连通性
		apiRouter.GET("/now", serverTime)
		// 相当于接口/api/Auth/ 的这组路径
		authRouter := apiRouter.Group("/auth").Use(middlewares.JwtVerify)
		{
			// 相当于接口 /api/Auth/login
			authRouter.POST("/login/", controller.Login)
			authRouter.POST("/register/", controller.Register)
			authRouter.POST("/logout/", controller.Logout)
			authRouter.POST("/verifyemail/", controller.VerifyEmail)
			authRouter.GET("/urlverify", controller.VerifyEmailURL)
			authRouter.POST("/codeverify/", controller.VerifyEmailCode) //a tip:验证emailcode后决定其他用途过于自由？有些情况下会有被攻击的风险，后面注意不能给前端太大的自由。即便接口是未知的，这里可以合并的。
			authRouter.POST("/emailchange/", controller.EmailChange)
			authRouter.GET("/qqauth", controller.QQAuth)
			authRouter.GET("/qqlogin", controller.QQLogin)
			authRouter.GET("/qqbind", controller.QQBind)
			authRouter.GET("/qqinfo", controller.QQInfo)
		}
		userRouter := apiRouter.Group("/user").Use(middlewares.JwtVerify)
		{
			userRouter.GET("/info", controller.UserInfo)
			userRouter.POST("/info/status/", controller.UserStatusInfo)
			userRouter.GET("/status/list", controller.UserStausList)
			userRouter.GET("/solution/list", controller.UserSolutionList)
			userRouter.POST("/edit/", controller.EditUserInfo)
			userRouter.POST("/edit/pass/", controller.EditUserPass)
			userRouter.POST("/vjudgeBind/", controller.VjudgeBind)
			userRouter.POST("/atcoderBind/", controller.AtcoderBind)
			userRouter.POST("/nowcoderBind/", controller.NowcoderBind)
			userRouter.POST("/codeforceBind/", controller.CodeForceBind)
			userRouter.POST("/editHead/", controller.EditImage)
			userRouter.POST("/forget/pass/", controller.PasswordForget)

			//组
			//管理员
			userRouter.POST("/group/add/", controller.AddGroup)
			userRouter.POST("/group/delete/", controller.DeleteGroup)
			userRouter.POST("/group/edit/", controller.EditGroup)//包含组任务,CID,PID,LID
			userRouter.POST("/group/list/", controller.GetGroupList)
			userRouter.GET("/group/:id", controller.GetGroup)
			userRouter.POST("/group/trans/",controller.GroupTransfer)
			userRouter.POST("/group/user/add/", controller.AddUserToGroup)
			userRouter.POST("/group/user/delete/", controller.DeleteUserFromGroup)
			//个人
			userRouter.POST("/group/join/", controller.JoinGroup)
			userRouter.POST("/group/quit/", controller.QuitGroup)
			userRouter.POST("/group/trace/", controller.GetGroupTrace)
		}
		adminRouter := apiRouter.Group("/admin").Use(middlewares.JwtVerify)
		{
			adminRouter.POST("/permission/edit/", controller.EditPermission)
			adminRouter.POST("/permission/delete/", controller.DeletePermission)
			adminRouter.POST("/permission/add/", controller.AddPermission)
			adminRouter.GET("/permission/list", controller.GetListPermission)
			adminRouter.GET("/permission/:id", controller.GetPermission)
			adminRouter.GET("/users",controller.GetUsers)
			adminRouter.POST("/users/Range/", controller.AddUsersRange)
			adminRouter.POST("/users/", controller.AddUsers)
			adminRouter.POST("/user/edit/", controller.AdminChangeUser)
		}

		problemRouter := apiRouter.Group("/problem").Use(middlewares.JwtVerify)
		{
			// ->  /api/problems/add/'
			problemRouter.POST("/add/", controller.AddProblem)       // 添加题目
			problemRouter.POST("/edit/", controller.EditProblem)     // 编辑题目
			problemRouter.POST("/delete/", controller.DeleteProblem) // 删除题目
			problemRouter.GET("/list", controller.GetProblemList)    // 获取题目列表
			// param 可以获取id
			problemRouter.GET("/:id", controller.GetProblem) // 获取题目
		}

		trainingRouter := apiRouter.Group("/training").Use(middlewares.JwtVerify)
		{
			trainingRouter.POST("/add/", controller.AddTraining)
			trainingRouter.POST("/edit/", controller.EditTraining)
			trainingRouter.POST("/user/", controller.RegisterTraining)
			trainingRouter.GET("/user", controller.GetTrainUserInfo)
			trainingRouter.POST("/delete/", controller.DeleteTraining)
			trainingRouter.GET("/list", controller.GetListTraining)
			trainingRouter.GET("/:id", controller.GetTraining)
			trainingRouter.GET("/:id/rank", controller.GetRankTraining)
			trainingRouter.POST("/clone/", controller.CloneTranining)
		} //其实这个可以和比赛合并，学长写了就不改了(

		contestRouter := apiRouter.Group("/contest").Use(middlewares.JwtVerify)
		{
			contestRouter.POST("/add/", controller.AddContest)
			contestRouter.POST("/edit/", controller.EditContest)
			contestRouter.POST("/delete/", controller.DeleteContest)
			contestRouter.POST("/clone/", controller.CloneContest)
			contestRouter.GET("/list", controller.GetListContest)
			contestRouter.GET("/base/:id",controller.GetBaseContest)
			contestRouter.GET("/:id", controller.GetContest)
			contestRouter.GET("/:id/rank", controller.GetRankContest)
			contestRouter.DELETE("/:id/rank", controller.DeleteWsRankClient)
			contestRouter.GET("/:id/rank/ws", controller.GetWsRankClient)
			contestRouter.POST("/color/", controller.UpdateConproColor)
			contestRouter.POST("/score/", controller.UpdateConproScore)
		}

		SubmitRouter := apiRouter.Group("/submit").Use(middlewares.JwtVerify)
		{
			SubmitRouter.POST("/commit/", controller.AddCommit)
			SubmitRouter.POST("/rejudge/", controller.RejudgeCommit)
			SubmitRouter.POST("rejudge/count/", controller.RejudgeCommitCount)
			SubmitRouter.GET("/status", controller.StatusList)
			SubmitRouter.GET("/:id", controller.GetCommit)
		}

		fileRouter := apiRouter.Group("/file").Use(middlewares.JwtVerify)
		{
			// 上传判题文件
			fileRouter.POST("/:pid/", controller.UpFile)
			fileRouter.POST("/:pid/generator/", controller.UpFile)
			fileRouter.POST("/:pid/validator/", controller.UpFile)
			fileRouter.GET("/:pid/:filename", controller.GetFile) //获取判题文件
			// 获取判题文件列表
			fileRouter.GET("/:pid", controller.GetFileList)
			// fileRouter.POST("/image/", controller.UpImagefile)
			// 删除文件
			fileRouter.DELETE("/:pid", controller.RemoveFile)
			// 解压文件
			fileRouter.POST("/unzip/:pid/", controller.UnzipFile)
			// 上传并解析题目
			fileRouter.POST("/problem/", controller.UpProblemFile)
			// 下载题目
			fileRouter.GET("/json/download", controller.DownloadProblemFromJson)
			// 上传题目
			fileRouter.POST("/problem/upfile/", controller.UpProblemFile)
		}
		ossRouter := apiRouter.Group("/oss").Use(middlewares.JwtVerify)
		{
			//-----------对象操作--------------
			ossRouter.POST("/object/get/", controller.GetObject) //获取base64/预签/下载文件
			ossRouter.POST("/object/put/", controller.PutObject)
			// 获取某个桶下面的所有文件
			ossRouter.GET("/object/:bucket", controller.GetObjects)
			//获取还未上传完成的列表
			// ossRouter.GET("/object/files", controller.GetUpingObjects)
			//从本地上传，暂时不需要上传其他来源数据，以后做(
			ossRouter.POST("/object/delete/", controller.DeleteObject)
			ossRouter.POST("/object/getfile/", controller.FGetObject) //下载本地
			ossRouter.POST("/object/putfile/", controller.FPutObject) //本地上传
			ossRouter.PUT("/object/modify/", controller.ModifyObject)
			ossRouter.POST("/object/info/", controller.GetObjectInfo)
			//-----------桶操作--------------
			//获得所有桶的名称+创建日期
			ossRouter.GET("/bucket", controller.GetBuckets)
			ossRouter.GET("/bucket/:bucket/stats", controller.GetBucketStats)
			ossRouter.GET("/bucket/:bucket/policy", controller.GetBucketPolicy)
			ossRouter.POST("/bucket/:bucket/policy/", controller.SetBucketPolicy)
			ossRouter.POST("/bucket/add/", controller.CreateBucket)
			ossRouter.POST("/bucket/delete/", controller.RemoveBucket)
		}
		noticeRouter := apiRouter.Group("/notice").Use(middlewares.JwtVerify)
		{
			noticeRouter.GET("/:id", controller.GetNotice)
			noticeRouter.POST("/", controller.CreateNotice)
			noticeRouter.DELETE("/:id", controller.DeleteNotice)
			noticeRouter.PUT("/:id", controller.UpdateNotice)
			noticeRouter.GET("/notices", controller.GetNoticeList)

			noticeRouter.GET("/images", controller.GetNoticeImages)
			noticeRouter.POST("/images/", controller.CreateNoticeImage)

			noticeRouter.GET("/data", controller.GetData)
		}
		toolRouter := apiRouter.Group("/tool").Use(middlewares.JwtVerify)
		{
			toolRouter.POST("/chat/", controller.AIChat)
			toolRouter.PUT("/chat", controller.UpdateAIChatState)
			toolRouter.GET("/chat", controller.GetAIChatList)
			toolRouter.POST("/sim/", controller.Sim)
		}
	}
	rediscache.EmailUrlVerifyPath = GetPathForHandler(router,controller.VerifyEmailURL)//便于修改路径
}

func NotFindRegister(ctx *gin.Context) {
	response.ResponseError(ctx, constanct.PageNotFoundCode)
}

// @Summary	Ping
// @Description
// @Tags		Ping
// @Accept		json
// @Produce	json
// @Success	200	{object}	response.Response
// @Router		/api/ping [get]
func PingTest(ctx *gin.Context) {
	ctx.JSON(http.StatusOK, gin.H{
		"code":    constanct.SuccessCode,
		"messgae": "",
	})
}

func serverTime(ctx *gin.Context) {
	ctx.JSON(http.StatusOK, gin.H{
		"Code": constanct.SuccessCode,
		"Msg":  "",
		"time": time.Now().UnixMilli(),
	})
}

func InitRouters(router *gin.Engine, host string) {
	conf := utils.GetConfInstance()
	logger := utils.GetLogInstance()
	for _, router := range router.Routes() {
		url := router.Path
		Method := router.Method
		req := request.AddRouterReq{
			FromURL:     url,
			Method:      Method,
			ToHost:      host,
			Weight:      10,
			VerfiyLevel: middlewares.GetVerifyUrl(url),
		}
		Header := make(map[string]string)
		Header["Content-Type"] = "application/json"
		dataByte, _ := json.Marshal(req)
		data := string(dataByte)
		for resp, _ := utils.DoRequest(utils.POST, conf.GatWayHost+"inner/addrouter", Header, nil, &data); resp.StatusCode != http.StatusOK; {
			logger.Errorf("add router error, status: %s", resp.Status)
			time.Sleep(10 * time.Second)
		}
	}
	logger.Info("add router success")
}

func GetPathForHandler(r *gin.Engine, handlerFunc interface{}) string {
	handlerFuncPtr := reflect.ValueOf(handlerFunc).Pointer()
	routes := r.Routes()
	for _, route := range routes {
		if reflect.ValueOf(route.HandlerFunc).Pointer() == handlerFuncPtr {
			return route.Path
		}
	}
	return ""
}